#include "Inode.h"


using namespace std;

	Inode::Inode(int inodeNum, int inodeOffset, int inodeIndirectBlockOffset, int blockSize) :
					number (inodeNum), offset(inodeOffset), type('f'),
					numOfHardLinks (0), fileSize (0),
					indirectBlockOffset (inodeIndirectBlockOffset), numOfAllocatedBlocks(0),
					maxBlocksCapacity (10+blockSize/4){
		for (int i=0; i<10; i++) {
			directBlocks[i] = -1;
		}
		indirectBlock.clear();
	}

	Inode::Inode (int inodeNum, int inodeOffset, char inodeType, int inodeNumOfHardLinks,
			int inodeFileSize, vector<int> inodeBlocks, int inodeIndirectBlockOffset, int blockSize) :
				number (inodeNum), offset(inodeOffset), type(inodeType),
				numOfHardLinks (inodeNumOfHardLinks), fileSize (inodeFileSize),
				indirectBlockOffset (inodeIndirectBlockOffset), numOfAllocatedBlocks(0),
				maxBlocksCapacity (10+blockSize/4) {
		for (int i=0; i<(int)inodeBlocks.size(); i++) {
			setDataBlock(i,inodeBlocks[i]);
		}

		cout << "Inode Number: " << number << endl;
		for (int i=0; i<(int)inodeBlocks.size(); i++) {
			cout << "Block " << i << ": " << getDataBlock(i) << endl;
		}
	}

	Inode::~Inode() {
		//delete (indirectBlock);
	}

	int Inode::getNumber() {
		return number;
	}

	int Inode::getIndirectBlockNum() {
		return indirectBlockOffset;
	}

	char Inode::getType() {
		return type;
	}
	void Inode::setType(char inodeType) {
		type = inodeType;
	}

	void Inode::incNumOfHardLinks() {
		numOfHardLinks++;
	}

	void Inode::decNumOfHardLinks() {
		numOfHardLinks--;
	}

	int Inode::getNumOfHardLinks() {
		return numOfHardLinks;
	}

	int Inode::getDataBlock (int i) {
		if (i < 0 || i > numOfAllocatedBlocks) {
			return -1;
		} else if (i<10) {
			return directBlocks[i];
		} else {
			return indirectBlock[i-10];
		}
	}

	int Inode::setDataBlock (int i, int dblock) {
		if (i < 0 || i > numOfAllocatedBlocks) {
			cerr << "Can`t set block " << i  << " in inode " << number << endl;
			return -1;
		} else {
			if (i == numOfAllocatedBlocks && i < maxBlocksCapacity) {
				numOfAllocatedBlocks++;
			}
			if (i < 10) {
				directBlocks[i] = dblock;
				return 0;
			} else {
				indirectBlock[i-10] = dblock;
				return 0;
			}
		}
	}

	int Inode::getOffset() {
		return offset;
	}

	int Inode::getFileSize () {
		return fileSize;
	}
	void Inode::setFileSize (int i) {
		fileSize = i;
	}

	void Inode::decreaseBlocksCounter() {
		numOfAllocatedBlocks--;
	}

	bool Inode::hasAllocatedBlocks() {
		return numOfAllocatedBlocks>0;
	}

	void Inode::writeToPhysicalDisk() {
		int fd = open("FILE_SYS", O_WRONLY, 0666);
		int buf;

		//goes to the location on the inode:
		lseek(fd,offset,SEEK_SET);

		//writes file type:
		int charSize = sizeof(char);
		write(fd, &type, charSize);

		//writes number of hard links:
		char numOfHL = numOfHardLinks;
		write(fd, &numOfHL, charSize);

		//writes files size (in bytes):
		write(fd, &fileSize, sizeof(int));

		//writes direct blocks addresses:
		int i=0;
		while (i<10 && i<numOfAllocatedBlocks) {
			buf = directBlocks[i];
			write(fd, &buf, sizeof(int));
			i++;
		}

		//writes the offset of the indirect block:
		lseek (fd,offset+46,SEEK_SET);
		write(fd, &indirectBlockOffset, sizeof(int));

		//goes to the location of the indirect block:
		lseek(fd,indirectBlockOffset,SEEK_SET);

		//writes indirect block address:
		for (int i=0; i<numOfAllocatedBlocks-10; i++) {
			buf = indirectBlock[i];
			write(fd, &buf, sizeof(int));
		}

		//closes the file
		close(fd);
	}
